﻿// Copyright 2009 - Johan de Koning (top2onenote@johandekoning.nl)
// 
// This file is part of the Top2OneNote AddIn
// The Top2OneNote AddIn is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// The Top2OneNote AddIn Library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using OneNote = Microsoft.Office.Interop.OneNote;
using System.Diagnostics;
using System.Windows.Forms;
using System.Windows.Ink;
using System.IO;
using System.Windows.Input;
using System.Xml.Linq;

namespace Top2OneNoteAddIn
{
    [Guid("9a4c9d19-e311-489b-9f60-444cab4c72d6")]
    public class Top2OneNote : IOneNoteAddIn
    {
        #region IOneNoteAddIn Members

        public bool OnClick(string strActivePageID)
        {   
            Process[] procs = Process.GetProcessesByName("OneNote");
            if (procs == null || procs.Length == 0)
            {
                return true;
            }

            IntPtr hwnd = procs[0].MainWindowHandle;

            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "top files (*.top)|*.top|All files (*.*)|*.*";
            dialog.Title = "Select a top file";
            if( dialog.ShowDialog(new WindowWrapper(hwnd)) != DialogResult.OK)
            {
                return true;
            }

            InkAnalyzer analyzer = new InkAnalyzer();

            Stream s = new FileStream(dialog.FileName, FileMode.Open);
            BinaryReader br = new BinaryReader(s);

            byte[] header = new byte[32];
            br.Read(header, 0, header.Length);

            StylusPointCollection pointCollection = new StylusPointCollection();
            double xcoordprev = 0.0;
            double ycoordprev = 0.0;
            bool drawing = false;
            
            while (true)
            {
                byte[] packet = new byte[6];
                int count = br.Read(packet, 0, packet.Length);
                if (count < 6) break;
               
                double xcoord = (packet[4] * 256 + packet[3]) / 10.0;
                double ycoord = (12000 - (packet[2] * 256 + packet[1])) / 10.0;

                if (packet[0] == 0)
                {
                    Stroke stroke = new Stroke(pointCollection);
                    analyzer.AddStroke(stroke);

                    pointCollection = new StylusPointCollection();
                    drawing = false;
                }
                else
                {
                    if (drawing)
                    {
                        pointCollection.Add(new StylusPoint(xcoordprev, ycoordprev));
                        pointCollection.Add(new StylusPoint(xcoord, ycoord));
                    }
                    else
                    {
                        pointCollection.Add(new StylusPoint(xcoord, ycoord));
                    }
                    xcoordprev = xcoord;
                    ycoordprev = ycoord;
                    drawing = true;
                }
            }

            br.Close();

            AnalysisStatus status = analyzer.Analyze();
            if (!status.Successful)
            {
                return true;
            }

            
            OneNote.ApplicationClass onApplication = new OneNote.ApplicationClass();

            XNamespace one = "http://schemas.microsoft.com/office/onenote/2007/onenote";
            XElement root = new XElement(one + "Page", new XAttribute(XNamespace.Xmlns + "one", one));
            root.Add(new XAttribute("ID", strActivePageID));

            BuildXML(analyzer.RootNode, root, one);

            onApplication.UpdatePageContent(root.ToString(), DateTime.MinValue);
            
            return true;
        }

        public bool OnEvent(OneNote.OneNoteAddIn_Event evt, string strParameter)
        {
            return true;
        }

        private void BuildXML(ContextNode contextNode, XElement xmlDocument, XNamespace oneNamespace)
        {
            foreach (var node in contextNode.SubNodes)
            {
                if (node is WritingRegionNode)
                {
                    WritingRegionNode wrNode = node as WritingRegionNode;

                    XElement outlineNode = new XElement(oneNamespace + "Outline");
                    xmlDocument.Add(outlineNode);

                    XElement positionNode = new XElement(oneNamespace + "Position");
                    positionNode.Add(new XAttribute("x", 0));
                    positionNode.Add(new XAttribute("y", 0));
                    outlineNode.Add(positionNode);

                    XElement sizeNode = new XElement(oneNamespace + "Size");
                    sizeNode.Add(new XAttribute("width", wrNode.Location.GetBounds().Width));
                    sizeNode.Add(new XAttribute("height", wrNode.Location.GetBounds().Height));
                    outlineNode.Add(sizeNode);

                    XElement OEChildrenNode = new XElement(oneNamespace + "OEChildren");
                    outlineNode.Add(OEChildrenNode);

                    XElement OENode = new XElement(oneNamespace + "OE");
                    OEChildrenNode.Add(OENode);

                    BuildXMLInkWords(node, OENode, oneNamespace);
                }
            }
        }

        private static void BuildXMLInkWords(ContextNode contextNode, XElement xmlDocument, XNamespace oneNamespace)
        {
            foreach (var node in contextNode.SubNodes)
            {
                if (node is InkWordNode)
                {
                    InkWordNode iwNode = node as InkWordNode;
                    XElement inkWordNode = new XElement(oneNamespace + "InkWord");
                    inkWordNode.Add(new XAttribute("recognizedText", iwNode.GetRecognizedString()));
                    xmlDocument.Add(inkWordNode);

                    XElement dataNode = new XElement(oneNamespace + "Data");
                    inkWordNode.Add(dataNode);

                    using (MemoryStream ms = new MemoryStream())
                    {
                        iwNode.Strokes.Save(ms);
                        byte[] isfBytes = ms.ToArray();
                        dataNode.SetValue(Convert.ToBase64String(isfBytes));
                    }
                }
                else
                {
                    BuildXMLInkWords(node, xmlDocument, oneNamespace);
                }
            }
        }
        #endregion
    }
}
